package examples;

import java.util.*;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Main {
    public static void main(String[] args) {
        //匿名类简写
        new Thread(() -> System.out.println("Hello Lambda expression!")).start();
        //Hello Lambda expression!

        //forEach
        List<String> someStrings = Arrays.asList("Lambda", "Hello", "expression", "Java");
        /*
         * Lambda
         * Hello
         * expression
         * Java
         */
        someStrings.forEach(n -> System.out.println(n));
        // 使用Java 8的方法引用更方便，方法引用由::双冒号操作符标示
        someStrings.forEach(System.out::println);
        /*
         * Lambda
         * Hello
         * expression
         * Java
         */

        //方法引用：
        //构造引用
        //Supplier<Student> s = ()-> new Student();
        Supplier<Student> s = Student::new;

        //对象::实例方法
        //Lambda表达式的(形参列表)与实例方法的(实参列表)类型，个数是对应的
        List<Integer> ints = Arrays.asList(1, 2, 3, 4);
        //ints.forEach(t-> System.out.println(t));
        ints.forEach(System.out::println);
        /*
         * 1
         * 2
         * 3
         * 4
         */

        //类名::静态方法
        //Stream<Double> stream = Stream.generate(() -> Math.random());
        Stream<Double> stream1 = Stream.generate(Math::random);

        //类名::实例方法
        TreeSet<String> strings = new TreeSet<>((s1, s2) -> s1.compareTo(s2));
        //String已经重写了compareTo()方法，在这里写是多此一举，这里为什么这么写，是因为为了体现下面
        //这句编译器的提示: Lambda can be replaced with method reference。
        //好了，下面的这句就是改写成方法引用之后:
        TreeSet<String> strings1 = new TreeSet<>(String::compareTo);

        System.out.println("____________________________________________");
        //Filter 与 Predicate 的常规用法
        List<String> languages = Arrays.asList("Java", "Scala", "C++", "Python", "C#");

        System.out.println("Languages which starts with J :");
        filter(languages, (str) -> str.startsWith("J"));

        System.out.println("Languages which ends with a :");
        filter(languages, (str) -> str.endsWith("a"));

        System.out.println("Print all languages :");
        filter(languages, (str) -> true);

        System.out.println("Print no language :");
        filter(languages, (str) -> false);

        System.out.println("Print language whose length greater than 4 :");
        filter(languages, (str) -> str.length() > 4);
        /*
         * ____________________________________________
         * Languages which starts with J :
         * Java
         * Languages which ends with a :
         * Java
         * Scala
         * Print all languages :
         * Java
         * Scala
         * C++
         * Python
         * C#
         * Print no language :
         * Print language whose length greater than 4 :
         * Scala
         * Python
         *
         * 进程已结束，退出代码为 0
         */

        System.out.println("____________________________________________________________________________________");
        //多个Predicate组合filter
        //可以用and() or() 和 xor()逻辑函数来合并Predicate
        //例如要找到所有以J开始，长度为四个字母的名字，我们可以合并两个Predicate并传入
        Predicate<String> startsWithJ = (n) -> n.startsWith("J");
        Predicate<String> fourLetterLong = (n) -> n.length() == 4;

        languages.stream()
                .filter(startsWithJ.and(fourLetterLong))
                .forEach((n) -> System.out.println("nName,which starts with 'J' and four letter long is : " + n));
        /*
         * ____________________________________________________________________________________
         * nName,which starts with 'J' and four letter long is : Java
         */

        System.out.println("__________________________________________________");
        //Map与Reduce
        //map将集合类(例如列表)元素进行转换，reduce()可以将所有值合并成一个
        List<Integer> someInts = Arrays.asList(100, 200, 300, 400, 500);
        double bill = someInts.stream().map((cost) -> cost + 1.2 * cost).reduce((sum, cost) -> sum + cost).get();
        System.out.println("Total : " + bill);//Total : 3300.0

        System.out.println("_______________________________________________________");
        //Collectors
        //将字符串转换成大写并用逗号链接起来
        List<String> G7 = Arrays.asList("USA", "Japan", "France", "Germany", "Italy", "U.K", "Canada");
        String G7Countries = G7.stream().map(String::toUpperCase).collect(Collectors.joining(", "));
        System.out.println(G7Countries);//USA, JAPAN, FRANCE, GERMANY, ITALY, U.K, CANADA

        System.out.println("____________________________________________________");
        //flatMap
        //将多个Stream连接成一个Stream
        List<Integer> result = Stream.of(Arrays.asList(1, 3), Arrays.asList(5, 6)).flatMap(Collection::stream).collect(Collectors.toList());
        System.out.println(result);//[1, 3, 5, 6]

        System.out.println("________________________________");
        //distinct 去重
        List<Student> students = new ArrayList<>();
        students.add(new Student("王", 1));
        students.add(new Student("张", 2));
        students.add(new Student("张", 22));
        students.add(new Student("李", 3));
        students.add(new Student("刘", 4));
        students.add(new Student("刘", 44));
        List<String> distinctByName = students.stream().map(Student::getName)
                .distinct().collect(Collectors.toList());
        System.out.println(distinctByName);//[王, 张, 李, 刘]

        System.out.println("_______________________________");
        //count 计数
        long cntOfStudent = students.stream()
                .filter(stu -> stu.getAge() > 18)
                .map(Adult::new).count();
        System.out.println(cntOfStudent);//2

        //Match


    }

    public static void filter(List<String> names, Predicate<String> condition) {
        names.stream().filter(condition).forEach((name) -> {
            System.out.println(name + " ");
        });
    }
}
